/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package me.weyye.hipermission.slice;

import static ohos.security.SystemPermission.LOCATION;
import static ohos.security.SystemPermission.LOCATION_IN_BACKGROUND;

import me.weyye.hipermission.AlertDialog;
import me.weyye.hipermission.ConstantValue;
import me.weyye.hipermission.PermissionAbility;
import me.weyye.hipermission.PermissionCallback;
import me.weyye.hipermission.PermissionDialog;
import me.weyye.hipermission.PermissionItem;
import me.weyye.hipermission.PermissionItemProvider;
import me.weyye.hipermission.ResourceTable;

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.window.dialog.CommonDialog;
import ohos.app.Context;
import ohos.bundle.IBundleManager;
import ohos.utils.IntentConstants;
import ohos.utils.net.Uri;

import java.util.List;
import java.util.ListIterator;

/**
 * 权限申请界面
 *
 * @since 2021-04-12
 */
public class PermissionAbilitySlice extends AbilitySlice {
    private Context mContext;
    public static final int PERMISSION_TYPE_SINGLE = 1;
    public static final int PERMISSION_TYPE_MUTI = 2;
    private int mPermissionType;
    private String mTitle;
    private String mMsg;
    private static PermissionCallback mCallback;
    private List<PermissionItem> mCheckPermissions;
    private PermissionDialog permissionDialog;

    private static final int REQUEST_CODE_SINGLE = 1;
    private static final int REQUEST_CODE_MUTI = 2;
    public static final int REQUEST_CODE_MUTI_SINGLE = 3;
    private static final int REQUEST_SETTING = 110;

    private CharSequence mAppName;
    private int mStyleId;
    private int mFilterColor;
    private int mAnimStyleId;

    private AlertDialog alertDialog;

    public static void setCallBack(PermissionCallback callBack) {
        PermissionAbilitySlice.mCallback = callBack;
    }

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_permission);
        PermissionAbility ability = (PermissionAbility) getAbility();
        ability.setAbilitySlice(this);
        getWindow().setTransparent(true);
        getWindow().setStatusBarVisibility(Component.VISIBLE);

        mContext = getContext();
        getDatas(intent);
        if (mPermissionType == PERMISSION_TYPE_SINGLE) {
            // 单个权限申请
            if (mCheckPermissions == null || mCheckPermissions.size() == 0) {
                return;
            }
            requestPermission(new String[]{mCheckPermissions.get(0).Permission}, REQUEST_CODE_SINGLE);
        } else {
            mAppName = getString(ResourceTable.String_app_name);
            // 多个权限
            showPermissionDialog();
        }
    }

    private String getPermissionTitle() {
        String permissionDialogTitle = mContext.getString(ResourceTable.String_permission_dialog_title);
        if (mTitle == null) {
            mTitle = "";
        }
        return mTitle.isEmpty() ? String.format(permissionDialogTitle, mAppName) : mTitle;
    }

    private void showPermissionDialog() {
        String title = getPermissionTitle();

        String permissionDialogMsg = mContext.getString(ResourceTable.String_permission_dialog_msg);
        if (mMsg == null) {
            mMsg = "";
        }
        String msg = mMsg.isEmpty() ? String.format(permissionDialogMsg, mAppName) : mMsg;

        permissionDialog = new PermissionDialog(this);
        permissionDialog.setTitle(title);
        permissionDialog.setMsg(msg);
        PermissionItemProvider provider = new PermissionItemProvider(mCheckPermissions);
        permissionDialog.setItemProvider(provider);

        if (mStyleId == -1) {
            // 用户没有设置，使用默认绿色主题
            mStyleId = ResourceTable.Pattern_PermissionDefaultNormalStyle;
            mFilterColor = ResourceTable.Color_permissionColorGreen;
        }

        permissionDialog.setStyleId(mStyleId);
        permissionDialog.setFilterColor(mFilterColor);
        permissionDialog.setBtnOnClickListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                permissionDialog.hide();
                String[] permissionStrArray = getPermissionStrArray();
                String[] permissions = new String[permissionStrArray.length + 1];
                for (int i = 0; i < permissionStrArray.length; i++) {
                    permissions[i] = permissionStrArray[i];
                    if (permissionStrArray[i].equals(LOCATION)) {
                        permissions[permissionStrArray.length] = LOCATION_IN_BACKGROUND;
                    }
                }
                requestPermissionsFromUser(permissions, REQUEST_CODE_MUTI);
            }
        });
        if (mAnimStyleId != -1) {
            permissionDialog.setAlignment(mAnimStyleId);
        }

        permissionDialog.setDestroyedListener(new CommonDialog.DestroyedListener() {
            @Override
            public void onDestroy() {
                if (mCallback != null) {
                    mCallback.onClose();
                }
                mContext.terminateAbility();
            }
        });
        permissionDialog.show();
        provider.notifyDataChanged();
    }

    private void reRequestPermission(final String permission) {
        String permissionName = getPermissionItem(permission).PermissionName;
        String alertTitle = String.format(mContext.getString(ResourceTable.String_permission_title), permissionName);
        String msg = String.format(mContext.getString(ResourceTable.String_permission_denied),
                permissionName, mAppName);
        showAlertDialog(alertTitle, msg, mContext.getString(ResourceTable.String_permission_cancel),
                mContext.getString(ResourceTable.String_permission_ensure), component -> {
                    alertDialog.hide();
                    requestPermission(new String[]{permission}, REQUEST_CODE_MUTI_SINGLE);
                });
    }

    private void requestPermission(String[] permissionStrArray, int requestCode) {
        String[] permissions = new String[permissionStrArray.length + 1];
        for (int i = 0; i < permissionStrArray.length; i++) {
            permissions[i] = permissionStrArray[i];
            if (permissionStrArray[i].equals(LOCATION)) {
                permissions[permissionStrArray.length] = LOCATION_IN_BACKGROUND;
            }
        }
        mContext.requestPermissionsFromUser(permissions, requestCode);
    }

    private void showAlertDialog(String title, String msg, String cancelTxt,
                                 String posTxt, Component.ClickedListener listener) {
        alertDialog = new AlertDialog(mContext);
        alertDialog.setTitle(title);
        alertDialog.setContent(msg);
        alertDialog.setSure(posTxt, listener);
        alertDialog.setCancel(cancelTxt, component -> {
            alertDialog.hide();
            onClose();
        });
        alertDialog.setDestroyedListener(() -> {
            if (mCallback != null) {
                mCallback.onClose();
            }
            mContext.terminateAbility();
        });
        alertDialog.show();
    }

    private String[] getPermissionStrArray() {
        String[] str = new String[mCheckPermissions.size()];
        for (int i = 0; i < mCheckPermissions.size(); i++) {
            str[i] = mCheckPermissions.get(i).Permission;
        }
        return str;
    }

    private void getDatas(Intent intent) {
        mPermissionType = intent.getIntParam(ConstantValue.DATA_PERMISSION_TYPE, PERMISSION_TYPE_SINGLE);
        mTitle = intent.getStringParam(ConstantValue.DATA_TITLE);
        mMsg = intent.getStringParam(ConstantValue.DATA_MSG);
        mFilterColor = intent.getIntParam(ConstantValue.DATA_FILTER_COLOR, 0);
        mStyleId = intent.getIntParam(ConstantValue.DATA_STYLE_ID, -1);
        mAnimStyleId = intent.getIntParam(ConstantValue.DATA_ANIM_STYLE, -1);
        mCheckPermissions = intent.getSerializableParam(ConstantValue.DATA_PERMISSIONS);
    }

    /**
     * 重新申请权限数组的索引
     */
    private int mRePermissionIndex;

    public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_SINGLE:
                String permission = getPermissionItem(permissions[0]).Permission;
                if (grantResults[0] == IBundleManager.PERMISSION_GRANTED) {
                    onGuarantee(permission, 0);
                } else {
                    onDeny(permission, 0);
                }
                mContext.terminateAbility();
                break;
            case REQUEST_CODE_MUTI:
                for (int i = 0; i < grantResults.length; i++) {
                    // 权限允许后，删除需要检查的权限
                    if (grantResults[i] == IBundleManager.PERMISSION_GRANTED) {
                        PermissionItem item = getPermissionItem(permissions[i]);
                        mCheckPermissions.remove(item);
                        onGuarantee(permissions[i], i);
                    } else {
                        // 权限拒绝
                        onDeny(permissions[i], i);
                    }
                }
                if (mCheckPermissions.size() > 0) {
                    // 用户拒绝了某个或多个权限，重新申请
                    reRequestPermission(mCheckPermissions.get(mRePermissionIndex).Permission);
                } else {
                    onFinish();
                }
                break;
            case REQUEST_CODE_MUTI_SINGLE:
                if (grantResults[0] == IBundleManager.PERMISSION_DENIED) {
                    // 重新申请后再次拒绝
                    // 弹框警告! haha
                    try {
                        // permissions可能返回空数组，所以try-catch
                        String name = getPermissionItem(permissions[0]).PermissionName;
                        String title = String.format(mContext.getString(ResourceTable.String_permission_title), name);
                        String msg = String.format(mContext.getString(ResourceTable.String_permission_denied_with_naac),
                                mAppName, name, mAppName);
                        showAlertDialog(title, msg, mContext.getString(ResourceTable.String_permission_reject),
                                mContext.getString(ResourceTable.String_permission_go_to_setting), component -> {
                                    alertDialog.hide();
                                    try {
                                        Intent intent = new Intent();
                                        intent.setAction(IntentConstants.ACTION_APPLICATION_DETAILS_SETTINGS);
                                        intent.setUri(Uri.parse("package:" + mContext.getBundleName()));
                                        mContext.startAbility(intent, REQUEST_SETTING);
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        onClose();
                                    }
                                });
                        onDeny(permissions[0], 0);
                    } catch (Exception e) {
                        e.printStackTrace();
                        onClose();
                    }
                } else {
                    onGuarantee(permissions[0], 0);
                    if (mRePermissionIndex < mCheckPermissions.size() - 1) {
                        // 继续申请下一个被拒绝的权限
                        reRequestPermission(mCheckPermissions.get(++mRePermissionIndex).Permission);
                    } else {
                        // 全部允许了
                        onFinish();
                    }
                }
                break;
            default:
                break;
        }
    }

    @Override
    public void onBackPressed() {
        mContext.terminateAbility();
    }

    @Override
    public void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
        super.onAbilityResult(requestCode, resultCode, resultData);
        if (requestCode == REQUEST_SETTING) {
            checkPermission();
            if (mCheckPermissions.size() > 0) {
                mRePermissionIndex = 0;
                reRequestPermission(mCheckPermissions.get(mRePermissionIndex).Permission);
            } else {
                onFinish();
            }
            if (permissionDialog != null && permissionDialog.isShowing()) {
                permissionDialog.hide();
            }
        }
    }

    private void checkPermission() {
        ListIterator<PermissionItem> iterator = mCheckPermissions.listIterator();
        while (iterator.hasNext()) {
            int checkPermission = mContext.verifySelfPermission(iterator.next().Permission);
            if (checkPermission == IBundleManager.PERMISSION_GRANTED) {
                iterator.remove();
            }
        }
    }

    private void onFinish() {
        if (mCallback != null) {
            mCallback.onFinish();
        }
        mContext.terminateAbility();
    }

    private void onClose() {
        if (mCallback != null) {
            mCallback.onClose();
        }
        mContext.terminateAbility();
    }

    private void onDeny(String permission, int position) {
        if (mCallback != null) {
            mCallback.onDeny(permission, position);
        }
    }

    private void onGuarantee(String permission, int position) {
        if (mCallback != null) {
            mCallback.onGuarantee(permission, position);
        }
    }

    private PermissionItem getPermissionItem(String permission) {
        for (PermissionItem permissionItem : mCheckPermissions) {
            if (permissionItem.Permission.equals(permission)) {
                return permissionItem;
            }
        }
        return null;
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (permissionDialog != null && permissionDialog.isShowing()) {
            permissionDialog.destroy();
        }
    }
}
